import sys
from PyQt4 import QtGui, QtCore
from box import *
from window import *
from enum_classes import *

        
def solve(boxes):
    for box_name in boxes :
        fill_parent_rec(boxes[box_name])

    main_boxes_dictionary = {}
    for box_name in boxes :
        if(boxes[box_name].parent == None):
            main_boxes_dictionary[box_name] = boxes[box_name]

    for box_name in main_boxes_dictionary :
        fill_childvars_childevents(main_boxes_dictionary[box_name])
        setBoxTypes(main_boxes_dictionary[box_name])
        main_boxes_dictionary[box_name].boxtype = BoxType.WINDOW
        

    win_dict = {}        
    for box_name in main_boxes_dictionary :
        solve_q_rec(main_boxes_dictionary[box_name])
        win_dict[box_name] = window(main_boxes_dictionary[box_name])
    #printRec( win_dict["main_window"].root_box , 0)
    return win_dict


def setBoxTypes(box):
    #add image
    if (box.boxtype == BoxType.EMPTY):
        flag = False
        if ( box.attributes.has_key("image")):
            flag = True
        for item in box.vars :
            if (box.vars[item] == GuiVariables.SETIMAGE):
                flag = True
        if( flag ):
            box.boxtype = BoxType.IMAGE

    #add frame
    if (box.boxtype == BoxType.EMPTY):
        if ( box.attributes.has_key("style")):
            box.boxtype = BoxType.FRAME

    #add splitter
    if (box.boxtype == BoxType.EMPTY):
        for event in box.events:
            if box.events[event]==GuiEvents.SPLITTER_MOVED:
                box.boxtype = BoxType.SPLITTER
                if (box.direction == BoxDirection.VERTICAL):
                    box.attributes["vertical"] = True
            
    for child in box.children :
        setBoxTypes(child)

    
def fill_childvars_childevents(box):
    for child in box.children :
         fill_childvars_childevents(child)
         box.child_vars = box.child_vars + child.child_vars
         box.child_events = box.child_events + child.child_events
         for item in child.vars :
             box.child_vars.append(item)
         for item in child.events :
             box.child_events.append(item)
         


def fill_parent_rec(box):
    for child in box.children :
        fill_parent_rec(child)
        child.parent = box


def solve_q_rec(box):
    if (box.direction == BoxDirection.HORIZONTAL):
        set_children_dimensions_H( box )
    if (box.direction == BoxDirection.VERTICAL):
        set_children_dimensions_V( box)
    for child in box.children :
        solve_q_rec(child)


def set_children_dimensions_H(box):
    
    children_combined_width = getMinWidth(box)
    children_max_hight = getMinHight(box)
    neededWidth = max( box.coordinates.w, children_combined_width)
    neededHight = max( box.coordinates.h, children_max_hight)
    difference = box.coordinates.w - children_combined_width
    x_cord = 0

    # add scrollbar
    if ( (difference < 0 ) | (children_max_hight > box.coordinates.h )):
        sc_bar_coord = Coordinates( 0, 0, box.coordinates.w, box.coordinates.h)
        sc_bar = Box(sc_bar_coord, BoxType.SCROLLAREA, box.child_vars, box.child_events, {}, {}, {}, [], box)
        emprt_wig_coord = Coordinates( 0, 0, neededWidth, neededHight)
        empty_wig = Box(emprt_wig_coord, BoxType.EMPTY, box.child_vars, box.child_events, {}, {}, {"scrollArea":1}, box.children, sc_bar)
        empty_wig.direction = BoxDirection.HORIZONTAL
        sc_bar.children = [empty_wig]
        for child in box.children :
            child.parent = empty_wig
        box.children = [sc_bar]
        return


    
    #set minimum width for children with known minimum
    #check for children with unbounded width
    new_width = []
    unbounded = []
    for child in box.children :
        if (child.coordinates.w != -1):
            new_width.append(child.coordinates.w)
        childMinWidth = getMinWidth(child)
        if ( (child.coordinates.w == -1)  &  (childMinWidth > 0) ):
            new_width.append(childMinWidth)
        if ( (child.coordinates.w == -1)  &  (childMinWidth == 0) ):
            new_width.append(0)
            
        if (isWidthBounded(child)):
            unbounded.append(0)
        else:
            unbounded.append(1)

    
    #devide remainder between children with unbound width
    if ( (difference > 0 ) & (unbounded.count(1) > 0) ) :
        avg_width = int( difference / unbounded.count(1) )
        missing_pix = difference - unbounded.count(1) * avg_width
        for i in range(len(box.children)) :
            if (unbounded[i] == 1) :
                new_width[i] += avg_width
        i=0
        j=0
        while(j < missing_pix):
            if (unbounded[i] == 1):
                new_width[i] += 1
                j += 1
            i+=1
            
    #finlize all children width
    for i in range(len(box.children)):
        box.children[i].coordinates.w = new_width[i]
             
        
    # width padding if necessery
    if ( (difference > 0 ) & (unbounded.count(1) == 0 ) ) :
         x_cord = int(difference/2)
        
    #set all x coordinates
    for child in box.children :
        child.coordinates.x = x_cord
        x_cord += child.coordinates.w

    # set all hights, hight padding and y coordinates
    for child in box.children :
        if ( (child.coordinates.h != -1) & (child.coordinates.h < neededHight) ):
            h_diff = neededHight - child.coordinates.h
            child.coordinates.y = int(h_diff/2)
        if ( child.coordinates.h == -1) :
            child.coordinates.h = neededHight


def set_children_dimensions_V(box):
    
    children_combined_hight = getMinHight(box)
    children_max_width = getMinWidth(box)
    neededHight = max( box.coordinates.h, children_combined_hight)
    neededWidth = max( box.coordinates.w, children_max_width)
    difference = box.coordinates.h - children_combined_hight
    y_cord = 0

    # add scrollbar
    if ( (difference < 0 ) | (children_max_width > box.coordinates.w )):
        sc_bar_coord = Coordinates( 0, 0, box.coordinates.w, box.coordinates.h)
        sc_bar = Box(sc_bar_coord, BoxType.SCROLLAREA, box.child_vars, box.child_events, {}, {}, {}, [], box)
        emprt_wig_coord = Coordinates( 0, 0, neededWidth, neededHight)
        empty_wig = Box(emprt_wig_coord, BoxType.EMPTY, box.child_vars, box.child_events, {}, {}, {"scrollArea":True}, box.children, sc_bar)
        empty_wig.direction = BoxDirection.VERTICAL
        sc_bar.children = [empty_wig]
        for child in box.children :
            child.parent = empty_wig
        box.children = [sc_bar]
        return
    
            
    #set minimum hight for children with known minimum
    #check for children with unbounded hight
    new_hight = []
    unbounded = []
    for child in box.children :
        if (child.coordinates.h != -1):
            new_hight.append(child.coordinates.h)
        childMinHight = getMinHight(child)
        if ( (child.coordinates.h == -1)  &  (childMinHight > 0) ):
            new_hight.append(childMinHight)
        if ( (child.coordinates.h == -1)  &  (childMinHight == 0) ):
            new_hight.append(0)
            
        if (isHightBounded(child)):
            unbounded.append(0)
        else:
            unbounded.append(1)

        
    #devide remainder between children with unbound hight
    if ( (difference > 0 ) & (unbounded.count(1) > 0) ) :
        avg_hight = int( difference / unbounded.count(1) )
        missing_pix = difference - unbounded.count(1) * avg_hight
        for i in range(len(box.children)) :
            if (unbounded[i] == 1) :
                new_hight[i] += avg_hight
        i=0
        j=0
        while(j < missing_pix):
            if (unbounded[i] == 1):
                new_hight[i] += 1
                j += 1
            i+=1
    #finlize all children hight
    for i in range(len(box.children)):
        box.children[i].coordinates.h = new_hight[i]
             
        
    # width padding if necessery
    if ( (difference > 0 ) & (unbounded.count(1) == 0 ) ) :
            y_cord = int(difference/2)
        
    #set all y coordinates
    for child in box.children :
        child.coordinates.y = y_cord
        y_cord += child.coordinates.h

    # set all widths, width padding and x coordinates
    for child in box.children :
        if ( (child.coordinates.w != -1) & (child.coordinates.w < neededWidth) ):
            w_diff = neededWidth - child.coordinates.w
            child.coordinates.x = int(w_diff/2)
        if ( child.coordinates.w == -1) :
            child.coordinates.w = neededWidth


def printRec(box, i):
    tub = ""
    for n in range(i):
        tub += "\t"
    print(tub + coord2String(box.coordinates))
    for child in box.children :
        printRec(child, i+1)

def coord2String(coord):
    return "( " + str(coord.x) + ", " + str(coord.y) + ", " + str(coord.w) + ", " + str(coord.h) + ")"


def getMinWidth(box):
    minWidth = 0
    if (box.direction == BoxDirection.HORIZONTAL):
        for child in box.children :
            minWidth += getMinWidth_rec(child)
    if (box.direction == BoxDirection.VERTICAL):
        cmw = 0
        for child in box.children :
            cmw = getMinWidth_rec(child)
            if ( cmw > minWidth):
                minWidth = cmw
    return minWidth
    
def getMinWidth_rec(box):
    minWidth = 0
    if ( box.coordinates.w != -1 ):
        minWidth = box.coordinates.w
    else:
        if (box.direction == BoxDirection.HORIZONTAL):
            for child in box.children :
                    minWidth += getMinWidth_rec(child)
        if (box.direction == BoxDirection.VERTICAL):
            cmw = 0
            for child in box.children :
                cmw = getMinWidth_rec(child)
                if ( cmw > minWidth):
                    minWidth = cmw
    return minWidth

def getMinHight(box):
    minHight = 0
    if (box.direction == BoxDirection.VERTICAL):
        for child in box.children :
                minHight += getMinHight_rec(child)
    if (box.direction == BoxDirection.HORIZONTAL):
        cmh = 0
        for child in box.children :
            cmh = getMinHight_rec(child)
            if ( cmh > minHight):
                minHight = cmh
    return minHight


def getMinHight_rec(box):
    minHight = 0
    if ( box.coordinates.h != -1 ):
        minHight = box.coordinates.h
    else:
        if (box.direction == BoxDirection.VERTICAL):
            for child in box.children :
                    minHight += getMinHight_rec(child)
        if (box.direction == BoxDirection.HORIZONTAL):
            cmh = 0
            for child in box.children :
                cmh = getMinHight_rec(child)
                if ( cmh > minHight):
                    minHight = cmh
    return minHight


def isWidthBounded(box):
    if ( box.coordinates.w != -1 ) :
        return 1
    if ( len(box.children) == 0):
        return 0
    for child in box.children:
        if ( ~isWidthBounded(child) ):
            return 0
    return 1

                

def isHightBounded(box):
    if ( box.coordinates.h != -1 ) :
        return 1
    if ( len(box.children) == 0):
        return 0
    for child in box.children:
        if ( ~isHightBounded(child) ):
            return 0
    return 1


